<template>
  <div>MarkText1</div>
  <div>
    <div style="margin-bottom: 30px">
      <label>开启标注：</label>
      <el-switch v-model="markSwitch"></el-switch>
      <div>
        <span>
          <label>展示标签：</label>
          <el-switch v-model="tagsSwitch"></el-switch>
        </span>
        <span v-if="markSwitch">
          <label>选择多段内容: </label>
          <input type="checkbox" id="multiSelect" v-model="multiSelect" />
        </span>
      </div>
    </div>
  </div>
  <div class="mark-box">
    <div
      class="text-container"
      @click="handleTextContainerClick"
      @mousedown="startSelection"
      @mouseup="endSelection"
      ref="textContainer"
    >
      <div ref="textParagraph"></div>
    </div>
    <div class="annotations">
      <h3>标注:</h3>
      <div v-if="markSwitch">
        <span>
          {{ '添加标签' }}
          <el-input v-model="label" placeholder="请输入标签"></el-input>
        </span>
        <div>
          <el-button @click="cancelSelection">取消</el-button>
          <el-button type="primary" @click="confirm"> 确认 </el-button>
        </div>
      </div>
      <h3>标注列表:</h3>
      <ul v-if="annotations.length">
        <li v-for="(annotation, index) in annotations" :key="index">
          {{ annotation.text }} - 标签: {{ annotation.label
          }}{{ annotation.tagList }}
          <button @click="removeAnnotation(index, annotation.tagList)">
            删除
          </button>
        </li>
      </ul>
    </div>
    <!-- 写一个对话框用于标签的添加和修改 -->
    <el-dialog
      v-model="dialogVisible"
      :modal="false"
      draggable
      width="300px"
      :close-on-click-modal="false"
      @close="cancelSelection"
    >
      <span>
        {{ '添加标签' }}
        <el-input v-model="label" placeholder="请输入标签"></el-input>
      </span>
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="cancelSelection">取消</el-button>
          <el-button type="primary" @click="confirm"> 确认 </el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>
<script setup>
  import { ref, onMounted, nextTick, watch } from 'vue';
  const markSwitch = ref(false);
  const tagsSwitch = ref(true);
  const text = ref(
    '昨天，长三角G60科创服务生态体系启动暨G60科创之眼推介大会在上海松江举行。“长三角G60科创之眼”作为上海长三角G60科创经济发展集团有限公司（以下简称“G60科创集团”）首个重大建设项目，是承载上海市与长三角其他区域资源要素流动的重要链接节点，也是长三角面向世界的重要窗口，旨在打造千亿级的科创新地标。\n\n  此外，长三角G60科创服务生态体系将打造国际化、市场化、标准化、品牌化的服务产品，提供从产业规划、产业招商到产业运营、产业服务全链条一站式服务，加速培育新质生产力，助力构建全国统一大市场。\n\n  现代化新型产业社区活力绽放\n\n  “长三角G60科创之眼”项目是G60科创集团成立后的第一个重大项目。项目规划总面积约1100亩，建成后将提供85万平方米的产业研发办公体、38万平方米的商业综合体和12万平方米的人才公寓，构建长三角G60科创走廊创新策源主阵地、高端产业聚集地、科创企业加速地、创新人才首选地。\n\n  G60科创集团总裁助理谭楠介绍说，长三角G60科创之眼作为现代化新型产业社区，建筑简洁、轻盈、线条流畅，既体现科技感又展现艺术性。下一步，将促进从地标到场景、从产业到人、从载体到社群的转变，使G60科创之眼区域成为一个充满活力的产业集聚区。\n\n  当天，长三角G60科创之眼首发地块包括12栋独栋办公楼及3栋塔楼，不少科技型企业提前布局落子，签订投资意向。“优赛科创集团将依托G60科创走廊的地理优势与政策支持，进一步联动长三角区域服务体系，打破地域界限，构建一个高效联动的长三角区域科创服务体系。”优赛科创集团董事长王金华表示，作为入驻园区的首家企业，将与G60科创集团紧密携手，取得更多发展机遇。\n\n  值得一提的是，“长三角G60科创之眼”项目创造了“当年拿地、当年开工、当年封顶、当年几乎实现销售”的G60速度。迄今为止，G60科创集团总投资超过50亿元，资产规模超过100亿元。\n\n  科创服务生态体系持续升级\n\n  优化创新生态，启动长三角G60科创服务生态体系建设是G60科创集团发展的另一先手棋。据介绍，长三角G60科创走廊九城市贡献全国1/15的GDP，拥有全国1/7的高新技术企业和超过1/5的科创板上市企业以及1020万个市场主体。\n\n  长三角G60科创服务生态体系将推动服务标准化建设，打造科研创新平台、标准管理以及科研体系数字化的三合一体的创新体系，把“让企业在长三角市场份额的有效增长、企业成本有效降低、服务舒适度有效提高”作为核心，更好优化产业生态、创新生态、服务生态，构建跨区域协同共享的服务体系。\n\n  同时，长三角G60科创服务生态体系将探索挖掘ChatGPT等大模型在新媒体领域的应用，通过新媒体方式，将过往以文字为信息的输出方式转换为当前流行的短视频和图文的信息输出方式，以瀑布流的模式展现，并通过底层算法将企业/个人/货品/信息进行四维循环匹配，实现多维度信息的高效流通和产业链的高度整合。\n\n  G60科创集团党委书记、董事长由杨表示，将建立长三角G60企业和人才数据库，推动高质量信息快速流动，形成新质生产力的孵化器和加速器，并在此基础上，与金融机构一起探索无抵押信用与技术贷款，为企业发展提供全生命周期的金融服务。\n\n  据悉，G60科创集团与国资委深度合作，共同成立“长三角G60国际商贸服务中心”，为长三角企业的出海以及海外订单的接洽全面对接服务，同时，还将与深圳市珠海市合作试点，尝试推动长三角与大湾区的企业形成产业链、供应链、人才链的深度融合，打通两地企业协同发展、联动招商的大通道，推动构建国内统一大市场，实现科创要素在两地的自由流通。',
  );
  const annotations = ref([
    {
      text: '昨天，',
      label: '项目名称',
      range: null,
      id: '0-2-abc',
    },
    { text: '流动的重要性', label: '公司名称', range: null, id: '115-120-def' },
    {
      text: '上海市与长三角其他区域资源要素流动的重要链接节点，也',
      label: '8546',
      range: null,
      id: '100-125-def',
    },
  ]);
  const multiSelect = ref(false);
  const activeSelection = ref(null);
  const activeMultiSelection = ref([]);
  const textContainer = ref(null);
  const textParagraph = ref(null);

  const dialogVisible = ref(false);
  const label = ref('');
  const tagCounter = ref(0);
  const confirm = () => {
    if (label.value && activeSelection.value) {
      // 没有开启多选的情况下
      if (!multiSelect.value) {
        activeSelection.value.label = label.value;
        let tagListStr = `tag-list${tagCounter.value++}`;
        activeSelection.value.tagList = tagListStr;
        annotations.value.push({ ...activeSelection.value });
        highlightRange(activeSelection.value.range, ['default', tagListStr]);
      } else {
        let tagListStr = `tag-list${tagCounter.value++}`;
        let minNum = null;
        activeMultiSelection.value.forEach((item, index) => {
          const [startOffset, endOffset] = item.id.split('-').map(Number);
          if (index === 0) {
            minNum = startOffset;
          } else {
            if (startOffset < minNum) {
              minNum = startOffset;
            }
          }
          item.label = label.value;
          item.tagList = tagListStr;
          annotations.value.push({ ...item });
          if (index === activeMultiSelection.value.length - 1) {
            // 高亮并传递标签位置
            highlightRange(item.range, ['default', tagListStr], minNum);
          } else {
            highlightRange(item.range, ['default', tagListStr]);
          }
        });
      }
    } else {
      // 提示框：完善label或者选取文本
      cancelSelection();
    }
    nextTick(() => {
      dialogVisible.value = false;
      label.value = '';
      activeSelection.value = null;
      activeMultiSelection.value = [];
    });
    console.log('标注列表', annotations.value);
  };

  const cancelSelection = () => {
    // 单选取消
    if (
      activeSelection.value &&
      activeSelection.value.id &&
      !multiSelect.value
    ) {
      removeSpanById(activeSelection.value.id);
    }
    // 多选取消
    if (activeMultiSelection.value.length > 0 && multiSelect.value) {
      activeMultiSelection.value.forEach((item) => {
        removeSpanById(item.id);
      });
    }
    nextTick(() => {
      dialogVisible.value = false;
      label.value = '';
      activeSelection.value = null;
      activeMultiSelection.value = [];
    });
  };

  onMounted(() => {
    textParagraph.value.textContent = text.value; // 确保文本内容插入到DOM中
    wrapTextWithSpans();
    annotations.value = annotations.value.map((annotation) => {
      return {
        ...annotation,
        tagList: `tag-list${tagCounter.value++}`,
      };
    });
    nextTick(() => {
      for (let i = 0; i < annotations.value.length; i++) {
        const annotation = annotations.value[i];
        highlightRangeById(annotation);
      }
    });
  });

  const highlightRangeById = (annotation) => {
    const { id, tagList, label } = annotation;
    const [startOffset, endOffset] = id.split('-').map(Number);
    const container = textParagraph.value;
    const spans = container.querySelectorAll('.word-list');
    for (let index = 0; index < spans.length; index++) {
      const span = spans[index];
      if (index >= startOffset && index <= endOffset) {
        span.classList.add('default', tagList);
        if (index.toString() === startOffset.toString()) {
          span.setAttribute('data-title', label);
        }
      }
    }
  };

  const removeSpanById = (id, tagList = null) => {
    const [startOffset, endOffset] = id.split('-').map(Number);
    const container = textParagraph.value;
    const spans = container.querySelectorAll('.word-list');

    let flag = true;
    for (let index = 0; index < spans.length; index++) {
      const span = spans[index];
      // 删除的时候需要根据tagList进行判断,批量删除
      const info = Array.from(span.classList).find(
        (className) => className === tagList,
      );
      // 根据tagList删除
      if (info !== undefined) {
        if (flag) {
          span.removeAttribute('data-title');
          flag = false;
        }
        span.classList.remove('new-tag', tagList);

        const tagListClass = Array.from(span.classList).find((className) =>
          className.startsWith('tag-list'),
        );
        if (tagListClass === undefined) {
          span.classList.remove('default');
        }
      }

      // 根据id取消选中的待标记文本
      if (index >= startOffset && index <= endOffset) {
        // 删除default时，需要确定没有taglist标签了
        span.classList.remove('new-tag', tagList);
        if (index.toString() === startOffset.toString()) {
          // 删除指定属性data-title
          span.removeAttribute('data-title');
        }
        const tagListClass = Array.from(span.classList).find((className) =>
          className.startsWith('tag-list'),
        );

        if (tagListClass === undefined) {
          span.classList.remove('default');
        }
      }
    }
  };

  const wrapTextWithSpans = () => {
    const container = textParagraph.value;
    const textContent = container.textContent;
    const spans = textContent.split('').map((char, index) => {
      const span = document.createElement('span');
      span.className = `word-list word${index} word_${index}`;
      span.textContent = char;
      return span;
    });
    container.innerHTML = ''; // 清空容器
    for (let i = 0; i < spans.length; i++) {
      const span = spans[i];
      container.appendChild(span);
    }
  };

  const handleTextContainerClick = (event) => {
    const target = event.target;
    if (target.classList.contains('word-list')) {
      const tagList = Array.from(target.classList).find((className) =>
        className.startsWith('tag-list'),
      );
      if (tagList) {
        const arr = Array.from(target.classList).filter((className) =>
          className.startsWith('tag-list'),
        );
        const matchingAnnotations = annotations.value.filter((annotation) =>
          arr.includes(annotation.tagList),
        );

        if (matchingAnnotations.length > 1) {
          // 按 text 长度排序，长度短的在前
          matchingAnnotations.sort((a, b) => a.text.length - b.text.length);
        }
        // 高亮第一个匹配的 annotation
        if (matchingAnnotations.length > 0) {
          highlightSpansByTagList(matchingAnnotations[0].tagList);
        }
      }
      // else {
      //   highlightSpansByTagList(null);
      // }
    }
  };

  const highlightSpansByTagList = (tagList) => {
    const container = textParagraph.value;
    const spans = container.querySelectorAll('.word-list');
    for (let i = 0; i < spans.length; i++) {
      const span = spans[i];
      if (span.classList.contains(tagList)) {
        span.classList.add('highlight'); // 添加高亮类
      } else {
        span.classList.remove('highlight'); // 移除高亮类
      }
    }
  };

  const startSelection = (event) => {
    // 判断是否开启标注状态
    if (!markSwitch.value) return;
    // 判断是否单选状态时，是否已经有选择
    if (!multiSelect.value && activeSelection.value) return;
    // 清除yellow高亮
    highlightSpansByTagList(null);
    activeSelection.value = {
      text: '',
      label: '',
      range: null,
      id: null,
    };
    window.getSelection().removeAllRanges();
  };

  const endSelection = (event) => {
    if (!markSwitch.value) return;
    if (!multiSelect.value && activeSelection.value.id) {
      return;
    }

    if (activeSelection.value) {
      const selection = window.getSelection();
      if (selection.rangeCount > 0) {
        const range = selection.getRangeAt(0);
        const selectedText = range.toString();
        if (selectedText) {
          activeSelection.value.text = selectedText;
          activeSelection.value.range = range;
          activeSelection.value.id = generateUniqueId(range);
          highlightRange(range, ['new-tag']);
          // 判断是否是多选
          if (multiSelect.value) {
            // activeMultiSelection
            activeMultiSelection.value.push(activeSelection.value);
            console.log('multi', activeMultiSelection.value);
          } else {
            // dialogVisible.value = true;
          }
        }
      }
    }
  };

  const highlightRange = (range, classNames, showTitlePosition = null) => {
    const startOffset =
      range.startContainer.parentNode.classList[2].split('_')[1];
    const endOffset = range.endContainer.parentNode.classList[2].split('_')[1];
    const container = textParagraph.value;
    const spans = container.querySelectorAll('.word-list');

    let pos = showTitlePosition === null ? startOffset : showTitlePosition; //标签位置
    for (let i = 0; i < spans.length; i++) {
      const span = spans[i];
      if (i >= startOffset && i <= endOffset) {
        span.classList.add(...classNames);
        if (classNames.includes('default')) {
          span.classList.remove('new-tag');
          if (i.toString() === pos.toString() && !multiSelect.value) {
            span.setAttribute('data-title', activeSelection.value.label);
          }
        }
      }
      // 多选时设置标签位置
      if (
        showTitlePosition !== null &&
        i.toString() === showTitlePosition.toString() &&
        multiSelect.value
      ) {
        span.setAttribute('data-title', activeSelection.value.label);
      }
    }
  };

  // const clearSelections = () => {
  //   const selection = window.getSelection();
  //   if (selection.rangeCount > 0) {
  //     selection.removeAllRanges();
  //   }
  // };

  const removeAnnotation = (index, tagList) => {
    const annotation = annotations.value.splice(index, 1)[0];
    const filteredAnnotations = annotations.value.filter(
      (item) => item.tagList !== tagList,
    );
    annotations.value = filteredAnnotations;
    // console.log(9999, filteredAnnotations);
    if (annotation && annotation.id) {
      highlightSpansByTagList(null); //移除高亮
      removeSpanById(annotation.id, annotation.tagList);
    } else {
      console.log('No valid annotation or range to remove');
    }
  };

  const generateUniqueId = (range) => {
    const startOffset =
      range.startContainer.parentNode.classList[2].split('_')[1];
    const endOffset = range.endContainer.parentNode.classList[2].split('_')[1];
    const randomChar = Math.random().toString(36).substr(2, 3);
    return `${startOffset}-${endOffset}-${randomChar}`;
  };
</script>
<style lang="scss" scoped>
  .mark-box {
    display: flex;
  }
  .text-container {
    width: 70vw;
  }
  .annotations {
    width: 25vw;
  }
  ::v-deep .word-list {
    position: relative; // 确保伪元素相对于这个元素定位
    white-space: pre-wrap;
    line-height: 1.4;
  }

  ::v-deep .word-list:before {
    content: attr(data-title);
    display: inline-block;
    width: 70px;
    line-height: 24px;
    text-align: center;
    color: #fff;
    background: #fc9845;
    border-radius: 6px;
    box-shadow: 0 6px 6px #00000014;
    position: absolute;
    left: 0;
    // transition: all ease 0.3s;
    top: -26px;
    font-size: 14px;
    height: 24px;
    opacity: v-bind('tagsSwitch ? 1 : 0'); // 初始状态隐藏
    pointer-events: none; // 确保伪元素不影响交互
  }

  ::v-deep .default {
    background-color: orange;
    color: white;
  }
  ::v-deep .new-tag {
    background-color: blue;
    color: white;
  }

  ::v-deep .highlight {
    background-color: yellow; // 设置高亮颜色
    color: black;
    // background-color: blue;
    // color: white;
  }
</style>
